package com.jasperframework.boot.common.utils;

import cn.hutool.crypto.symmetric.AES;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;

/**
  * <p>  </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */
public class CryptoUtil {

    private final static String IV = "1234567890123456";//需要前端与后端配置一致
    private final static String KEY = "1234567890123456";

    private final static String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private final static String DES_ALGORITHM = "DES/ECB/PKCS5Padding";


    /**
     * 加密算法，使用默认的IV、KEY
     * @param content
     * @return
     */
    public static String encrypt(String content) throws Exception {
        return encrypt(content,KEY,IV);
    }

    /**
     * 解密算法，使用默认的IV、KEY
     * @param content
     * @return
     */
    public static String decrypt(String content){
        return decrypt(content,KEY,IV);
    }
    /**
     * 加密方法
     * @param content
     * @param key
     * @param iv
     * @return
     */
    public static String encrypt(String content, String key, String iv){
        try{
            // "算法/模式/补码方式"NoPadding PkcsPadding
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            // NoPadding 补码方式时，可能会出现少于16字节的情况，需要手动对不足16位的字节数组进行补位，以保证明文的长度是加密块大小的整数倍，确保加密和解密操作的正确执行
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = content.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);
            return BASE64Utils.getEncodeBase64(encrypted);
        }catch (Exception e) {
            throw new RuntimeException("加密算法异常 CryptoUtil encrypt()加密方法，异常信息：" + e.getMessage());
        }
    }

    /**
     * 解密方法
     * @param content
     * @param key
     * @param iv
     * @return
     */
    public static String decrypt(String content, String key, String iv){
        try {
            byte[] encrypted1 = BASE64Utils.decodeBase64(content);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] original = cipher.doFinal(encrypted1);
            return new String(original).trim();
        } catch (Exception e) {
            throw new RuntimeException("加密算法异常 CryptoUtil decrypt()解密方法，异常信息：" + e.getMessage());
        }
    }

    public static void main(String[] args) throws Exception {
        // 添加Bouncy Castle作为加密提供程序，就能够使用支持AES/CBC/PKCS7Padding的加密算法
         Security.addProvider(new BouncyCastleProvider());
//        String encryptText = encrypt("hello");
//
//        System.out.println("encryptText = " + encryptText);
//
//        String decryptText = decrypt(encryptText);
//
//        System.out.println("decryptText = " + decryptText);


        AES aes = new AES("CBC", "PKCS7Padding",
                // 密钥，可以自定义
                "1234567890123456".getBytes(),
                // iv加盐，按照实际需求添加
                "1234567890123456".getBytes());

// 加密为16进制表示
        String encryptHex = aes.encryptBase64("hello");

        System.out.println("encryptHex = " + encryptHex);
// 解密
        String decryptStr = aes.decryptStr(encryptHex);

        System.out.println("decryptStr = " + decryptStr);
    }
}
